package com.guqj.nio.netty.tcp;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * @Title TcpServer
 * @Description netty tcp粘包服务端
 * @date 2016年11月17日
 */
public class TcpServer {

	public void bind(int port) throws InterruptedException {
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup wokerGroup = new NioEventLoopGroup();

		try {
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, wokerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
					.childHandler(new ServerChannelInitializer());
			Channel c = b.bind(port).sync().channel();
			System.out.println("服务已经启动,端口:" + port);
			c.closeFuture().sync();
		} finally {
			bossGroup.shutdownGracefully();
			wokerGroup.shutdownGracefully();
			System.out.println("服务销毁!");
		}
	}

	class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
		@Override
		protected void initChannel(SocketChannel ch) throws Exception {
			/*
			 * 以下代码为了解决半包读问题
			 * 
			 * LineBasedFrameDecoder是回车换行解码器，如果用户发送的消息以回车换行符作为消息结束的标识，
			 * 则可以直接使用Netty的LineBasedFrameDecoder对消息进行解码
			 * 
			 * DelimiterBasedFrameDecoder 分隔符解码器
			 * 
			 * FixedLengthFrameDecoder 固定长度解码器 无论一次接收到多少数据包，都会按照构造函数中设置的固定长度进行解码，如果是半包，则会缓存半包消息并
			 * 等待下个包后进行拼包，直到取到一个完整的包
			 * 
			 * StringDecoder 字符串解码器
			 */
			ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
			//ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
			//ch.pipeline().addLast(new DelimiterBasedFrameDecoder(4096, delimiter));
			// ch.pipeline().addLast(new FixedLengthFrameDecoder(20));
			ch.pipeline().addLast(new StringDecoder());

			ch.pipeline().addLast(new TcpServerHandler());
		}
	}

	public static void main(String[] args) throws InterruptedException {
		new TcpServer().bind(11013);
	}
}
